package com.qingcheng.timer;

import com.qingcheng.dao.SeckillGoodsMapper;
import com.qingcheng.dao.SeckillOrderMapper;
import com.qingcheng.pojo.goods.Goods;
import com.qingcheng.pojo.seckill.SeckillGoods;
import com.qingcheng.pojo.seckill.SeckillOrder;
import com.qingcheng.util.DateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import tk.mybatis.mapper.entity.Example;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Set;

@Component
public class SeckillGoodsTask {

    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 定时任务方法
     * 从每分钟的第0秒开始执行，每过30秒执行一次
     */
    @Scheduled(cron = "0/3 * * * * ?")
    public void loadGoods(){

        //1.获取时间段集合
        List<Date> dateMenus = DateUtil.getDateMenus();

        //2循环时间段
        for(Date startTime:dateMenus){

            Example example = new Example(SeckillGoods.class);
            Example.Criteria criteria = example.createCriteria();

            //2.1审核通过的 status="1"
            criteria.andEqualTo("status","1");

            //2.2库存>0
            criteria.andGreaterThan("stockCount",0);

            //2.3活动开始时间<=开始时间 个人这么理解，与老师的相反 活动开始时间>=开始时间,后来感觉秒杀商品应该就这么设置，要不然怎么叫秒杀呢
            criteria.andLessThanOrEqualTo("startTime",startTime);

            //2.4活动结束时间>=开始时间+2  个人这么理解，与老师的相反 活动结束时间<开始时间+2
            criteria.andGreaterThanOrEqualTo("endTime",DateUtil.addDateHour(startTime,2));

            //2.5过滤掉redis缓存的商品数据
            Set keys = redisTemplate.boundHashOps("SeckillGoods_" + DateUtil.date2Str(startTime)).keys();
            if(keys!=null && keys.size()>0){
                criteria.andNotIn("id",keys);
            }

            //2.6执行查询
            List<SeckillGoods> seckillGoodsList = seckillGoodsMapper.selectByExample(example);

            //3.将秒杀商品数据存入到redis缓存
            for(SeckillGoods seckillGood: seckillGoodsList){
//                System.out.println("key:"+"SeckillGoods_"+DateUtil.date2Str(startTime));
                redisTemplate.boundHashOps("SeckillGoods_"+DateUtil.date2Str(startTime)).put(seckillGood.getId(),seckillGood);

                //商品数据队列存储，防止高并发超卖
                //剩余库存个数 seckillGoods.getStockCount() = 5
                //创建对立队列 存储商品剩余库存
                // [100,100,100,100,100]
//                System.out.println("库存:"+seckillGood.getStockCount());
                Long[] ids = pushIds(seckillGood.getStockCount(), seckillGood.getId());
//                System.out.println(ids.length);

//                redisTemplate.boundListOps("SeckillGoodsCountList_"+seckillGood.getId()).leftPushAll(ids); 这种写法可能会多次执行，因为我设置的商品的有效时间有点大，所以每个时间段都会执行
                //所以略微做个修改
                redisTemplate.boundListOps("SeckillGoodsCountList_"+DateUtil.date2Str(startTime)+"_"+seckillGood.getId()).leftPushAll(ids);


                //创建自定key的值 解决并发情况下商品数量不稳定问题 ,这个是单线程安全
                redisTemplate.boundHashOps("SeckillGoodsCount"+DateUtil.date2Str(startTime)).increment(seckillGood.getId(),seckillGood.getStockCount());


            }
        }

    }

    /**
     * 将商品ID存入到数组中
     * @param len 长度
     * @param id 值
     * @return
     */
    public Long[] pushIds(int len,Long id){
        Long[] ids = new Long[len];
        for(int i=0;i<ids.length;i++){
            ids[i]=id;
        }
        return ids;
    }

}
